package com.qf.smartdevice.service.Impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.qf.smartdevice.cache.AreaCache;
import com.qf.smartdevice.cache.CategoriesCache;
import com.qf.smartdevice.cache.DevicesCache;
import com.qf.smartdevice.constans.ResultCode;
import com.qf.smartdevice.event.DevicesCacheChangeEvent;
import com.qf.smartdevice.event.PowerCommandEvent;
import com.qf.smartdevice.exceptions.QuaryDataException;
import com.qf.smartdevice.mapper.DevicesMapper;
import com.qf.smartdevice.pojo.Areas;
import com.qf.smartdevice.pojo.Categories;
import com.qf.smartdevice.pojo.Devices;
import com.qf.smartdevice.service.IDevicesService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@EnableAspectJAutoProxy(proxyTargetClass = true)
@Transactional
public class DevicesServiceImpl implements IDevicesService {
    @Autowired
    private DevicesMapper devicesMapper;
    @Autowired
    private CategoriesCache categoriesCache;
    @Autowired
    private AreaCache areaCache;
    @Autowired
    private DevicesCache devicesCache;
    @Autowired
    private DevicesCacheChangeEvent event;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    ApplicationContext context;

    @Override

    public PageInfo<Devices> findAllDevices(int page, int limit, String address, Long areaid1, Long categoryid1, Long status, Long areasearch) {

//        PageHelper.startPage(page, limit);
        List<Devices> allDevicess = devicesCache.getAllData();
        List<Devices> allDevices = allDevicess.stream().filter(devices -> {
            Boolean addresss = true;
            Boolean areaid11 = true;
            Boolean categoryid11 = true;
            Boolean status1 = true;
            Boolean areasearch1 = true;
            String address1 = devices.getAddress();
            Long categoryid = devices.getCategoryid();
            String status2 = devices.getStatus();
            Long areaid = devices.getAreaid();


            if (address != null && address != "") {
                addresss = address1.contains(address);
            }
            if (status != null && status != -100) {
                Long aLong = Long.valueOf(status2);
                status1 = status == aLong;
            }
            if (categoryid1 != null && categoryid1 != -100 && categoryid1 != -1) {
                categoryid11 = categoryid == categoryid1;
            }
            if (areaid1 != null && -100 != areaid1) {
                areaid11 = areaid1 == areaid;
            }
            return addresss && status1 && categoryid11 && areaid11;
        }).collect(Collectors.toList());


//       这个数据只有自己的基本信息  分类和区域信息没有
//        List<Devices> allDevices = devicesMapper.findAllDevices();
//        从缓存中取到相关数据 设置到对象
        allDevices.forEach(devices -> {
            Long areaid = devices.getAreaid();//区域ID
            Long categoryid = devices.getCategoryid();//设备ID

            Areas areas = areaCache.getObj(areaid);
            Categories obj = categoriesCache.getObj(categoryid);
//            从缓存中获取的区域和分类 设置到当前遍历对象上面
            devices.setArea(areas);
            devices.setCategory(obj);
        });
        PageInfo pageInfo = null;
//         集合切割
        int last_index = limit;
        if (page * limit >= allDevices.size()) {
            last_index = allDevices.size();
        } else {
            last_index = page * limit;
        }
        if ((page - 1) * limit >= allDevices.size()) {
            pageInfo = new PageInfo();
            return pageInfo;
        }

        List<Devices> devicesList = allDevices.subList((page - 1) * limit, last_index);
        pageInfo = new PageInfo(devicesList);
        pageInfo.setTotal(allDevices.size());
        return pageInfo;
    }

    @Override
    public int devicesById(int[] ids) {

        int i = devicesMapper.devicesById(ids);
        devicesCache.onEvent(event);
        return i;
    }


    @Override
    public int insertDevices(Devices devices) {
        int i = devicesMapper.insertDevices(devices);
        devicesCache.onEvent(event);
        return i;
    }

    @Override
    public int updateByIdDevice(Devices devices) {
        int i = devicesMapper.updateByIdDevice(devices);
        devicesCache.onEvent(event);

        return i;
    }

    @Override
    public void sendControl(String uuid, String command) throws JsonProcessingException {
        //我们的目的不是向设备发送命令
        // 但是command赢不是真正的命令， 他只是命令对应的一个key,需要从分类中获取真正的命令
//         分类怎么获取  每个设备对应一个分类 我们需要从设备中获取
//        设备怎么获取  我们有一个唯一的UUID  根据UUID  可以查询到设备分类的ID  然后我们有分类缓存 可以根据分类ID 从缓存中获取到分类的数据
        Long categoryId = devicesMapper.getCategoryIdByUUID(uuid);
        if (categoryId == null) {
            throw new QuaryDataException("设备编号不存在", ResultCode.NULL_DATA);
        }

//        在分类的对象有一个属性记录了命令的映射  我们可以获取到
        Categories categories = categoriesCache.getObj(categoryId);
        //获取到指令的映射,是一个 json 字符串
        String txcommand = categories.getTxcommand();
        Map map = objectMapper.readValue(txcommand, Map.class);
        Object o = map.get(command);
        if (o instanceof Map) {
            Object type = ((Map<?, ?>) o).get("type");
            Object value = ((Map<?, ?>) o).get("value");
            if (type.toString().equals("1")) {
//                执行的是向电器设备发送指令 发送的真正指令内容就是value
//                向设备发送数据是通过webscoket 实现的 所以在这里我们需要找到这个设备对应的websocket
//                方式1 要么我们在这边获取到保存所有绘画的map 通过UUID拿连接 发送指令
//                方式2  让websocket  自己执行 在他内部可以直接获取到所有的会话
//                方式 2 比较合适,因为可以不用和 websocket 直接建立关系,降低耦合度

                context.publishEvent(new PowerCommandEvent(uuid, command));
            } else if (type.toString().equals("2")) {
//                向颜色控制器发送指令
            }
        }
    }


    /*
     *
     * */
    @EventListener
    public void onEvent(DevicesCacheChangeEvent event) {
        String deviceuuid = event.getDeviceuuid();
        String status = event.getStatus();
//        更新状态
        devicesMapper.updateStatusByUUID(deviceuuid, status);
        System.err.println("设备" + deviceuuid + "的更新结果为" + status);
    }
}
